﻿using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using SapaFinance.DTO;
using SapaFinance.Domain;
using SapaFinance.Domain.BusinessLogic;
using SapaFinance.Domain.Model;
using SapaFinance.GenericRepository;

namespace SapaFinance.Services
{
    public interface IRequestService
    {
        RequestDTO Clone(Guid id);
        IEnumerable<RequestDTO> GetListDTO();
        void Delete(Guid id);
        void Update(RequestDTO dto);
        void Insert(RequestDTO dto);
        IEnumerable<string> VerifyAggregateToOrder(Guid[] checkedRecords);
        Request GetRequest(Guid guid);
        ICombineToOrderCompositeRule CombineToOrderRule { get; set; }
        IBudgetItemService BudgetItemService { get; set; }
        ICorporationService CorporationService { get; set; }
        ICfoService CFOService { get; set; }
        IAccountService AccountService { get; set; }
        IPaymentTypeService PaymentTypeService { get; set; }
    }

    public class RequestService : IRequestService
    {
        private readonly IEntityFactory _entityFactory;
        private readonly IMappingEngine _mappingEngine;
        private readonly IGenericRepository<Request,Guid> _requestRepository;
        private readonly IUnitOfWork _unitOfWork;

        public RequestService(IGenericRepository<Request, Guid> requestRepository, IMappingEngine mappingEngine, IUnitOfWork unitOfWork,
                              IEntityFactory entityFactory)
        {
            _requestRepository = requestRepository;
            _mappingEngine = mappingEngine;
            _unitOfWork = unitOfWork;
            _entityFactory = entityFactory;
        }

        public ICombineToOrderCompositeRule CombineToOrderRule { get; set; }
        public IBudgetItemService BudgetItemService { get; set; }
        public ICorporationService CorporationService { get; set; }
        public ICfoService CFOService { get; set; }
        public IAccountService AccountService { get; set; }
        public IPaymentTypeService PaymentTypeService { get; set; }
        public IUserService UserService{ get; set; }

        #region IRequestService Members

        public RequestDTO Clone(Guid id)
        {
            var requestDto = _mappingEngine.Map<Request, RequestDTO>(_requestRepository.GetById(id));
            requestDto.UID = Guid.Empty;
            return requestDto;
        }

        public IEnumerable<RequestDTO> GetListDTO()
        {
            var requests = _requestRepository.Specify<IRequestSpecification>().OrderByPaymentPeriod().ToResult().ToList();
            return _mappingEngine.Map<IEnumerable<Request>, IEnumerable<RequestDTO>>(requests);
        }

        public void Delete(Guid id)
        {
            var request = _requestRepository.GetById(id);
            if (request != null){
                _requestRepository.Delete(request);
                _unitOfWork.Flush();
            }
        }

        public void Update(RequestDTO dto)
        {
            var budgetitem = BudgetItemService.GetBudgetItem(dto.SelectedBudgetItem);
            var payer = CorporationService.GetCorporation(dto.SelectedPayer);
            var department = CFOService.GetCfo(dto.SelectedCfo);
            var account = AccountService.GetAccount(dto.SelectedAccount.HasValue ? dto.SelectedAccount.Value : Guid.Empty);
            var payee = CorporationService.GetCorporation(dto.SelectedPayee.HasValue ? dto.SelectedPayee.Value : Guid.Empty);
            var paymentType = PaymentTypeService.GetPaymentType(dto.SelectedPaymentType);
            var request = _requestRepository.GetById(dto.UID);
            var user = UserService.GetUser(dto.CurrentUser);
            if (user != null){
                request.Description = dto.Description;
                request.PaymentPeriod = dto.PaymentPeriod;
                request.PaymentPurpose = dto.PaymentPurpose;
                request.SetPayee(payee);
                request.SetPayer(payer);
                request.SetPayeeAccount(account);
                request.SetDepartment(department);
                request.SetBudgetItem(budgetitem);
                request.SetTaxRate(dto.TaxRate);
                request.SetPayment(dto.Payment.HasValue ? dto.Payment.Value : 0);
                request.SetPaymentType(paymentType);
                request.Change(user);
                _requestRepository.Update(request);
                _unitOfWork.Flush();
            }
        }

        public void Insert(RequestDTO dto)
        {
            var entity = _entityFactory.BuildRequest(dto);
            _requestRepository.Insert(entity);
            _unitOfWork.Flush();
        }

        public IEnumerable<string> VerifyAggregateToOrder(Guid[] requestsIDs)
        {
            var requests = requestsIDs.Select(x => _requestRepository.GetById(x));
            if (requests.Count() > 1){
                var oneRequest = requests.First();
                CombineToOrderRule.SetObjectToMatch(oneRequest);
                foreach (var request in requests)
                    CombineToOrderRule.IsValid(request);
                return CombineToOrderRule.GetBrokenRules();
            }
            return new List<string>();
        }

        public Request GetRequest(Guid guid)
        {
            return _requestRepository.GetById(guid);
        }

        #endregion
    }
}